﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Common;
using Microsoft.TeamFoundation.WorkItemTracking.Controls;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.IO;
using System.Security.Principal;
using System.DirectoryServices;
using System.Diagnostics;

namespace WitPhotoCustomControl
{
    public class PhotoControl : UserControl, IWorkItemControl, IWorkItemToolTip, IWorkItemUserAction, IWorkItemClipboard
    {
        private PictureBox CurrentPhotoPictureBox;

        #region Constants

        private const long MAX_FILE_SIZE_IN_BYTES = 10 * 1024;
        private const int MAX_IMAGE_HEIGHT_IN_PIXELS = 96;
        private const int MAX_IMAGE_WIDTH_IN_PIXELS = 96;
        private const string USER_SEARCH_TEMPLATE = "(&(objectCategory=user)(objectClass=user)(displayName={0}))";

        #endregion



        #region Private Fields

        private SearchResult _cachedResult;

        #endregion

        #region Constructor

        public PhotoControl()
        {
            InitializeComponent();
        }

        #endregion

        #region IWorkItemControl implementation

        public event EventHandler AfterUpdateDatasource;

        public event EventHandler BeforeUpdateDatasource;

        public void Clear()
        {
            return;
        }

        public void FlushToDatasource()
        {
            return;
        }

        public void InvalidateDatasource()
        {
            return;
        }

        private System.Collections.Specialized.StringDictionary _properties;
        public System.Collections.Specialized.StringDictionary Properties
        {
            get
            {
                return _properties;
            }
            set
            {
                _properties = value;
            }
        }

        public bool ReadOnly
        {
            get
            {
                return false;
            }
            set
            {
            }
        }

        public void SetSite(IServiceProvider serviceProvider)
        {
        }

        private WorkItem _workItem;
        public object WorkItemDatasource
        {
            get
            {
                return _workItem;
            }
            set
            {
                if (_workItem != null)
                {
                    _workItem.FieldChanged -= OnBoundFieldChanged;
                }

                _workItem = value as WorkItem;

                if (_workItem != null)
                {
                    _workItem.FieldChanged += OnBoundFieldChanged;
                }
            }
        }

        private string _workItemFieldName;
        public string WorkItemFieldName
        {
            get
            {
                return _workItemFieldName;
            }
            set
            {
                _workItemFieldName = value;
            }
        }

        #endregion

        #region IWorkItemToolTip implementation

        private Label _label;
        public Label Label
        {
            get
            {
                return _label;
            }
            set
            {
                _label = value;
            }
        }

        private ToolTip _toolTip;
        public ToolTip ToolTip
        {
            get
            {
                return _toolTip;
            }
            set
            {
                _toolTip = value;
            }
        }

        #endregion

        #region IWorkItemUserAction implementation

        public event EventHandler UserActionRequiredChanged;

        private Color _highlightBackColor;
        public Color HighlightBackColor
        {
            get
            {
                return _highlightBackColor;
            }
            set
            {
                _highlightBackColor = value;
            }
        }

        private Color _highlightForeColor;
        public Color HighlightForeColor
        {
            get
            {
                return _highlightForeColor;
            }
            set
            {
                _highlightForeColor = value;
            }
        }

        private string _requiredText;
        public string RequiredText
        {
            get
            {
                return _requiredText;
            }
            set
            {
                _requiredText = value;
            }
        }

        public bool UserActionRequired
        {
            get
            {
                return false;
            }
        }

        #endregion

        #region IWorkItemClipboard implementation

        public event EventHandler ClipboardStatusChanged;

        public bool CanCopy
        {
            get
            {
                return false;
            }
        }

        public bool CanCut
        {
            get
            {
                return false;
            }
        }

        public bool CanPaste
        {
            get
            {
                return false;
            }
        }

        public void Copy()
        {
        }

        public void Cut()
        {
        }

        public void Paste()
        {
        }

        #endregion

        #region Private Methods

        private void OnBoundFieldChanged(object sender, WorkItemEventArgs e)
        {
            if (e.Field != null)
            {
                // Refresh the photo since the field value has changed to another user.
                LoadUserProfile();
            }
        }

        private void LoadUserProfile()
        {
            // Erase the current image, if any.
            CurrentPhotoPictureBox.Image = null;

            string displayName = string.Empty;
            if (_workItem != null && !string.IsNullOrWhiteSpace(_workItemFieldName))
            {
                if (!string.IsNullOrWhiteSpace(_workItemFieldName))
                {
                    displayName = (string)_workItem.Fields[_workItemFieldName].Value;
                }
            }

            if (string.IsNullOrEmpty(displayName))
            {
                // Could not get current user name.
                return;
            }

            // Get user profile from AD.
            using (DirectoryEntry root = new DirectoryEntry())
            {
                string adQuery = string.Format(USER_SEARCH_TEMPLATE, displayName.Replace(" ", "\\20"));

                using (DirectorySearcher searcher = new DirectorySearcher(root, adQuery, new string[] { "userPrincipalName" }))
                {
                    searcher.Asynchronous = false;
                    searcher.SearchScope = SearchScope.Subtree;
                    SearchResult result = searcher.FindOne();

                    if (result == null || string.IsNullOrEmpty(result.Path))
                    {
                        Trace.WriteLine(string.Format("Could not get user profile for '{0}'.", displayName));
                        return;
                    }

                    try
                    {
                        using (DirectoryEntry user = result.GetDirectoryEntry())
                        {
                            _cachedResult = result;

                            byte[] thumbnailPhoto = user.Properties["thumbnailPhoto"].Value as byte[];

                            if (thumbnailPhoto != null)
                            {
                                using (MemoryStream stream = new MemoryStream(thumbnailPhoto))
                                {
                                    CurrentPhotoPictureBox.Image = Image.FromStream(stream); // can fail if the binary stream is not a valid photo
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Trace.WriteLine(string.Format("Error getting user photo. Message: {0}.", ex.Message));
                    }
                }
            }
        }

        #endregion

        private void InitializeComponent()
        {
            this.CurrentPhotoPictureBox = new System.Windows.Forms.PictureBox();
            ((System.ComponentModel.ISupportInitialize)(this.CurrentPhotoPictureBox)).BeginInit();
            this.SuspendLayout();
            // 
            // CurrentPhotoPictureBox
            // 
            this.CurrentPhotoPictureBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.CurrentPhotoPictureBox.Location = new System.Drawing.Point(0, 0);
            this.CurrentPhotoPictureBox.Margin = new System.Windows.Forms.Padding(0);
            this.CurrentPhotoPictureBox.Name = "CurrentPhotoPictureBox";
            this.CurrentPhotoPictureBox.Size = new System.Drawing.Size(96, 96);
            this.CurrentPhotoPictureBox.TabIndex = 3;
            this.CurrentPhotoPictureBox.TabStop = false;
            // 
            // PhotoControl
            // 
            this.Controls.Add(this.CurrentPhotoPictureBox);
            this.Name = "PhotoControl";
            this.Size = new System.Drawing.Size(96, 96);
            this.Load += new System.EventHandler(this.PhotoControl_Load);
            ((System.ComponentModel.ISupportInitialize)(this.CurrentPhotoPictureBox)).EndInit();
            this.ResumeLayout(false);

        }

        private void PhotoControl_Load(object sender, EventArgs e)
        {
            // Load the profile photo for the bound work item field since it will be available at this point.
            LoadUserProfile();
        }
    }
}
